package com.sikaryofficial.system.controller;

import cn.hutool.core.text.CharSequenceUtil;
import com.sikaryofficial.common.core.constant.CacheConstants;
import com.sikaryofficial.common.core.domain.R;
import com.sikaryofficial.common.core.exception.ServiceException;
import com.sikaryofficial.common.core.utils.DateUtils;
import com.sikaryofficial.common.core.utils.StringUtils;
import com.sikaryofficial.common.core.utils.file.FileTypeUtils;
import com.sikaryofficial.common.core.utils.file.MimeTypeUtils;
import com.sikaryofficial.common.core.web.controller.BaseController;
import com.sikaryofficial.common.core.web.domain.AjaxResult;
import com.sikaryofficial.common.log.annotation.Log;
import com.sikaryofficial.common.log.enums.BusinessType;
import com.sikaryofficial.common.redis.service.RedisService;
import com.sikaryofficial.common.security.service.TokenService;
import com.sikaryofficial.common.security.utils.SecurityUtils;
import com.sikaryofficial.system.api.RemoteFileService;
import com.sikaryofficial.system.api.domain.SysFile;
import com.sikaryofficial.system.api.domain.SysUser;
import com.sikaryofficial.system.api.model.LoginUser;
import com.sikaryofficial.system.api.model.SysUserEmailReq;
import com.sikaryofficial.system.api.model.SysUserNickNameReq;
import com.sikaryofficial.system.manager.UserAgeCacheManager;
import com.sikaryofficial.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Objects;

import static com.sikaryofficial.common.core.constant.CacheConstants.SEND_MAIL_CAPTCHA_KEY;

/**
 * 个人信息 业务处理
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/user/profile")
@Slf4j
public class SysProfileController extends BaseController {
    @Autowired
    private ISysUserService userService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private RemoteFileService remoteFileService;
    @Autowired
    private UserAgeCacheManager userAgeCacheManager;
    @Value("${hismk.user.ageLimit}")
    private Integer limitAge;
    @Resource
    private RedisService redisService;

    /**
     * 个人信息
     */
    @GetMapping
    public AjaxResult profile() {
        String username = SecurityUtils.getUsername();
        SysUser user = userService.selectUserByUserName(username);
        AjaxResult ajax = AjaxResult.success(user);
        ajax.put("roleGroup", userService.selectUserRoleGroup(username));
        ajax.put("postGroup", userService.selectUserPostGroup(username));
        return ajax;
    }

    /**
     * 修改用户
     */
    @Log(title = "个人信息修改", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult updateProfile(@RequestBody SysUser user, @RequestHeader("deviceId") String deviceId, @RequestHeader("channel") String channel) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser currentUser = loginUser.getSysUser();
        currentUser.setNickName(user.getNickName());
        currentUser.setEmail(user.getEmail());
        currentUser.setPhonenumber(user.getPhonenumber());
        currentUser.setSex(user.getSex());
        // 新增字段
        currentUser.setFirstName(user.getFirstName());
        currentUser.setLastName(user.getLastName());
        currentUser.setCareer(user.getCareer());
        currentUser.setBirthDate(user.getBirthDate());
        // 新增多个字段
        currentUser.setReferralCode(user.getReferralCode());
        currentUser.setSex(user.getSex());

        // 年龄参数验证
        if (Objects.nonNull(user.getBirthDate())) {
            Integer age = DateUtils.getAgeByBirthDate(user.getBirthDate());
            if (age < limitAge) {
                log.error("modify userid'" + user.getUserId() + "'fail, age is less than " + limitAge);
                return error("age is less than " + limitAge);
            }
        }
        if (StringUtils.isNotEmpty(user.getPhonenumber()) && userService.checkPhoneUnique(currentUser)) {
            log.error("modify PhoneNumber'" + user.getPhonenumber() + "'fail");
            return error("PhoneNumber is exist.");
        }
        if (userService.updateUserProfile(currentUser) > 0) {
            // 更新年龄缓存
            userAgeCacheManager.updateUserAgeCache(currentUser);
            // 更新缓存用户信息
            tokenService.setLoginUser(loginUser);
            return success();
        }
        return error("Abnormal modification of personal information, please contact the administrator.");
    }

    /**
     * 更新年龄缓存
     *
     * @param sysUser
     */
    private void updateUserAgeCache(SysUser sysUser) {
        // 设置年龄缓存
        String catchKey = MessageFormat.format(CacheConstants.USER_AGE_KEY, sysUser.getUserId().toString());
        if (Objects.nonNull(sysUser.getBirthDate())) {
            // 设置年龄缓存
            redisService.setCacheObject(catchKey, DateUtils.getAgeByBirthDate(sysUser.getBirthDate()));
        }
    }

    /**
     * 重置邮箱
     */
    @Log(title = "个人邮箱信息更新", businessType = BusinessType.UPDATE)
    @PostMapping("/updateEmail")
    public AjaxResult updateEmail(@Validated @RequestBody SysUserEmailReq req, @RequestHeader("deviceId") String deviceId, @RequestHeader("channel") String channel) {
        Long userId = SecurityUtils.getUserId();
        SysUser user = userService.selectUserById(userId);
        log.error("user:{}", user);
        String inputEmail = req.getEmail();
        SysUser currentUser = new SysUser();
        currentUser.setUserId(user.getUserId());
        currentUser.setEmail(req.getEmail());
        // 判定待修改邮箱是否已经存在
        if (CharSequenceUtil.isBlank(inputEmail)) {
            throw new ServiceException("modify email could not be empty");
        }
        if (userService.checkEmailUnique(currentUser)) {
            log.error("modify userid'" + user.getUserId() + "'fail, age is less than " + limitAge);
            return error("email is exist.");
        }
        // 获取输入的邮箱验证码 与 缓存中的是否一致
        String realKey = MessageFormat.format(SEND_MAIL_CAPTCHA_KEY, inputEmail);
        String mailCaptcha = redisService.getCacheObject(realKey);
        logger.info("cache Captcha : " + mailCaptcha + ";inputEmail：" + inputEmail + ";inputCaptcha：" + req.getCaptcha());
        if (!StringUtils.equals(mailCaptcha, req.getCaptcha())) {
            return error("Verification code error.");
        }
        // old_email
        String oldEmail = user.getEmail();
        if (userService.resetEmail(userId, inputEmail, oldEmail) > 0) {
            // 更新缓存用户密码
            LoginUser loginUser = SecurityUtils.getLoginUser();
            loginUser.getSysUser().setEmail(inputEmail);
            tokenService.setLoginUser(loginUser);
            return success();
        }
        return error("Abnormal modification of email. Please contact the administrator.");
    }

    /**
     * 重置密码
     */
    @Log(title = "个人密码修改", businessType = BusinessType.UPDATE)
    @PutMapping("/updatePwd")
    public AjaxResult updatePwd(String oldPassword, String newPassword) {
        String username = SecurityUtils.getUsername();
        SysUser user = userService.selectUserByUserName(username);
        String password = user.getPassword();
        if (!SecurityUtils.matchesPassword(oldPassword, password)) {
            return error("修改密码失败，旧密码错误");
        }
        if (SecurityUtils.matchesPassword(newPassword, password)) {
            return error("新密码不能与旧密码相同");
        }
        if (userService.resetUserPwd(username, SecurityUtils.encryptPassword(newPassword)) > 0) {
            // 更新缓存用户密码
            LoginUser loginUser = SecurityUtils.getLoginUser();
            loginUser.getSysUser().setPassword(SecurityUtils.encryptPassword(newPassword));
            tokenService.setLoginUser(loginUser);
            return success();
        }
        return error("修改密码异常，请联系管理员");
    }


    /**
     * 头像上传
     */
    @Log(title = "修改昵称", businessType = BusinessType.UPDATE)
    @PostMapping("/updateNickName")
    public AjaxResult updateNickName(@RequestBody SysUserNickNameReq req) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Long userId = loginUser.getUserid();
        int count = userService.nickNameCount(userId,req.getNickName());
        if(count > 0){
            log.info("nickName:{},count:{}",req.getNickName(),count);
            return error("Repeat nick name");
        }
        if (userService.updateNickName(userId, req.getNickName())) {
            AjaxResult ajax = AjaxResult.success();
            ajax.put("nickName", req.getNickName());
            // 更新缓存用户头像
            loginUser.getSysUser().setNickName(req.getNickName());
            tokenService.setLoginUser(loginUser);
            // TODO： 更新缓存数据
            userAgeCacheManager.updateNickNameCache(userId, req.getNickName());
            return ajax;
        }
        return error("Update nick name error");
    }

    /**
     * 头像上传
     */
    @Log(title = "用户头像修改", businessType = BusinessType.UPDATE)
    @PostMapping("/avatar")
    public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file, @RequestHeader("deviceId") String deviceId, @RequestHeader("channel") String channel) {
        if (!file.isEmpty()) {
            LoginUser loginUser = SecurityUtils.getLoginUser();
            Long userId = loginUser.getUserid();
            String extension = FileTypeUtils.getExtension(file);
            if (!StringUtils.equalsAnyIgnoreCase(extension, MimeTypeUtils.IMAGE_EXTENSION)) {
                return error("The file format is incorrect, please upload format : " + Arrays.toString(MimeTypeUtils.IMAGE_EXTENSION));
            }
            R<SysFile> fileResult = remoteFileService.upload(file);
            if (StringUtils.isNull(fileResult) || StringUtils.isNull(fileResult.getData())) {
                return error("File service exception, please contact the administrator.");
            }
            String url = fileResult.getData().getUrl();
            if (userService.updateUserAvatar(userId, url)) {
                AjaxResult ajax = AjaxResult.success();
                ajax.put("imgUrl", url);
                // 更新缓存用户头像
                loginUser.getSysUser().setAvatar(url);
                tokenService.setLoginUser(loginUser);
                // TODO： 更新缓存数据
                userAgeCacheManager.updateAvatarCache(userId, url);
                return ajax;
            }
        }
        return error("The file service is abnormal. Please contact the administrator to upload images. Please contact the administrator.");
    }

    /**
     * 用户背景图片上传
     */
    @Log(title = "用户背景图片修改", businessType = BusinessType.UPDATE)
    @PostMapping("/backImg")
    public AjaxResult backImg(@RequestParam("file") MultipartFile file, @RequestHeader("deviceId") String deviceId, @RequestHeader("channel") String channel) {
        if (!file.isEmpty()) {
            LoginUser loginUser = SecurityUtils.getLoginUser();
            String extension = FileTypeUtils.getExtension(file);
            if (!StringUtils.equalsAnyIgnoreCase(extension, MimeTypeUtils.IMAGE_EXTENSION)) {
                return error("The file format is incorrect, please upload format : " + Arrays.toString(MimeTypeUtils.IMAGE_EXTENSION));
            }
            R<SysFile> fileResult = remoteFileService.upload(file);
            if (StringUtils.isNull(fileResult) || StringUtils.isNull(fileResult.getData())) {
                return error("File service exception, please contact the administrator.");
            }
            String url = fileResult.getData().getUrl();
            if (userService.updateUserBackImg(SecurityUtils.getUserId(), url)) {
                AjaxResult ajax = AjaxResult.success();
                ajax.put("imgUrl", url);
                // 更新缓存用户背景图片
                loginUser.getSysUser().setBackImg(url);
                tokenService.setLoginUser(loginUser);
                // TODO： 更新缓存数据
                userAgeCacheManager.updateBackImgCache(loginUser.getSysUser().getUserId(),url);
                return ajax;
            }
        }
        return error("The file service is abnormal. Please contact the administrator to upload images. Please contact the administrator.");
    }
}
